<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Plugins\QrCode;

use Srv\Libs\Common\CommString;

!defined('QR_EC_LEVEL_L')       && define('QR_EC_LEVEL_L',          0);
!defined('QR_EC_LEVEL_M')       && define('QR_EC_LEVEL_M',          1);
!defined('QR_EC_LEVEL_Q')       && define('QR_EC_LEVEL_Q',          2);
!defined('QR_EC_LEVEL_H')       && define('QR_EC_LEVEL_H',          3);
!defined('QR_MODE_NUL')         && define('QR_MODE_NUL',            -1);
!defined('QR_MODE_NUM')         && define('QR_MODE_NUM',            0);
!defined('QR_MODE_AN')          && define('QR_MODE_AN',             1);
!defined('QR_MODE_8')           && define('QR_MODE_8',              2);
!defined('QR_MODE_KANJI')       && define('QR_MODE_KANJI',          3);
!defined('QR_MODE_STRUCTURE')   && define('QR_MODE_STRUCTURE',      4);
!defined('QR_SPEC_VERSION_MAX') && define('QR_SPEC_VERSION_MAX',    40);
!defined('QR_CAP_WIDTH')        && define('QR_CAP_WIDTH',           0);
!defined('QR_CAP_WORDS')        && define('QR_CAP_WORDS',           1);
!defined('QR_CAP_REMINDER')     && define('QR_CAP_REMINDER',        2);
!defined('QR_CAP_EC')           && define('QR_CAP_EC',              3);
!defined('QR_N1')               && define('QR_N1',                  3);
!defined('QR_N2')               && define('QR_N2',                  3);
!defined('QR_N3')               && define('QR_N3',                  40);
!defined('QR_N4')               && define('QR_N4',                  10);

class QrCode
{
    /**
     * @param string $text
     * @param int $level
     * @return array
     * getData
     */
    public static function getData(string $text, int $level = QR_EC_LEVEL_L):array
    {
        return QrEncode::factory($level)->encode($text);
    }

    /**
     * @param array $qrData
     * @param int $imageSize
     * @param int $margin
     * @param string $fgColor
     * @param string $bgColor
     * @return string
     * getPng
     */
    public static function getPng(array $qrData, int $imageSize = 128, int $margin = 5, string $fgColor = '000000FF', string $bgColor = 'FFFFFF00'):string
    {
        $imageSize      = max($imageSize, 0);
        $margin         = max($margin, 0);
        $fgColorR       = $fgColorG = $fgColorB = $fgColorA = -1;
        if(CommString::parseColorStr($fgColor, $fgColorR, $fgColorG, $fgColorB, $fgColorA)){
            $fgColorA   = $fgColorA >= 0 ? intval(round((255 - $fgColorA)/255*127, 0)) : 0; // 默认0[0-不透明,127-全透明]
            if($fgColorR === 0 && $fgColorG === 0 && $fgColorB === 0) $fgColorB = 1;        // 纯黑色特殊处理
        }else{
            $fgColorR   = $fgColorG = $fgColorB = 0;
            $fgColorA   = 0;
        }
        $bgColorR       = $bgColorG = $bgColorB = $bgColorA = -1;
        if(CommString::parseColorStr($bgColor, $bgColorR, $bgColorG, $bgColorB, $bgColorA)){
            $bgColorA   = $bgColorA >= 0 ? intval(round((255 - $bgColorA)/255*127, 0)) : 0; // 默认0[0-不透明,127-全透明]
            if($bgColorR === 0 && $bgColorG === 0 && $bgColorB === 0) $bgColorB = 1;        // 纯黑色特殊处理
        }else{
            $bgColorR   = $bgColorG = $bgColorB = 255;
            $bgColorA   = 0;
        }
        $rowNum         = count($qrData);
        $colNum         = strlen($qrData[0]);
        $isDstImage     = $imageSize > 0;
        $imageWidth     = $imageHeight = max($rowNum, $colNum) + ($isDstImage ? 0 : (2 * $margin));
        if($fgColorA > 0 || $bgColorA > 0){
            $isTrans    = true;
            $imageSrc   = imagecreatetruecolor($imageWidth, $imageHeight);
        }else{
            $isTrans    = false;
            $imageSrc   = imagecreate($imageWidth, $imageHeight);
        }
        if($isTrans) imagecolortransparent($imageSrc, imagecolorallocatealpha($imageSrc, 0, 0, 0, 127));
        $colorBg        = $bgColorA === 0 ? imagecolorallocate($imageSrc, $bgColorR, $bgColorG, $bgColorB) : imagecolorallocatealpha($imageSrc, $bgColorR, $bgColorG, $bgColorB, $bgColorA);
        $colorFg        = $fgColorA === 0 ? imagecolorallocate($imageSrc, $fgColorR, $fgColorG, $fgColorB) : imagecolorallocatealpha($imageSrc, $fgColorR, $fgColorG, $fgColorB, $fgColorA);
        if(!$isTrans) imagefill($imageSrc, 0, 0, $colorBg);
        for($i = 0; $i < $rowNum; $i++){
            for($j = 0; $j < $colNum; $j++){
                $qrPointVal     = $qrData[$i][$j]??'';
                $colorPoint     = $qrPointVal === '1' ? $colorFg : $colorBg;
                if($colorPoint !== false){
                    $marginSet  = $isDstImage ? 0 : $margin;
                    imagesetpixel($imageSrc, $j + $marginSet, $i + $marginSet, $colorPoint);
                }
            }
        }
        if($isDstImage){
            $margin         = min($margin, intval($imageSize/2));
            $imageDstWidth  = $imageDstHeight = $imageSize;
            $imageDst       = imagecreatetruecolor($imageDstWidth, $imageDstHeight);
            if($isTrans) imagecolortransparent($imageDst, imagecolorallocatealpha($imageDst, 0, 0, 0, 127));
            if(!$isTrans){
                $dstColorR          = $dstColorG = $dstColorB = $dstColorA = -1;
                // 优先原图透明设置
                $imageSrcIndex      = imagecolortransparent($imageSrc);
                if($imageSrcIndex >= 0){
                    $srcColorTran   = imagecolorsforindex($imageSrc, $imageSrcIndex);
                    $dstColorR      = intval($srcColorTran['red']??-1);
                    $dstColorG      = intval($srcColorTran['green']??-1);
                    $dstColorB      = intval($srcColorTran['blue']??-1);
                    $dstColorA      = intval($srcColorTran['alpha']??-1);
                }
                // 其次背景透明设置
                if($dstColorR < 0 || $dstColorG < 0 || $dstColorB < 0){
                    $dstColorR      = $bgColorR;
                    $dstColorG      = $bgColorG;
                    $dstColorB      = $bgColorB;
                    $dstColorA      = $bgColorA;
                }
                $colorDstBg         = $dstColorA === 0 ? imagecolorallocate($imageDst, $dstColorR, $dstColorG, $dstColorB) : imagecolorallocatealpha($imageDst, $dstColorR, $dstColorG, $dstColorB, $dstColorA);
                imagefill($imageDst, 0, 0, $colorDstBg);
            }
            imagecopyresized($imageDst, $imageSrc, $margin, $margin, 0, 0, $imageDstWidth-2*$margin, $imageDstHeight-2*$margin, $imageWidth, $imageHeight);
            ob_start();
            imagepng($imageDst);
            $imageStr       = ob_get_contents();
            ob_end_clean();
            imagedestroy($imageDst);
        }else{
            ob_start();
            imagepng($imageSrc);
            $imageStr       = ob_get_contents();
            ob_end_clean();
        }
        imagedestroy($imageSrc);
        return $imageStr;
    }

    /**
     * @param array $qrData
     * @return string
     * getTerminalStr
     */
    public static function getTerminalStr(array $qrData):string
    {
        $shellStr           = '';
        $qrDataSize         = count($qrData);
        for($i = 0; $i < $qrDataSize; $i += 2){
            $lineOne        = $qrData[$i]??'';
            $lineTwo        = $qrData[$i+1]??'';
            $lineMaxLength  = max(strlen($lineOne), strlen($lineTwo));
            for($j = 0; $j < $lineMaxLength;$j++){
                $one = ord($lineOne[$j]??'')&1 ? '1' : '0';
                $two = ord($lineTwo[$j]??'')&1 ? '1' : '0';
                switch ($one.$two){
                    case '11':{ $shellStr .= '█'; break; }
                    case '10':{ $shellStr .= '▀'; break; }
                    case '01':{ $shellStr .= '▄'; break; }
                    case '00':{ $shellStr .= ' '; break; }
                }
            }
            $shellStr     .= "\n";
        }
        return strlen($shellStr) > 0 ? substr($shellStr, 0, -1) : $shellStr;
    }
}